Imports Aricie.DNN.Caching
Imports Aricie.DNN.Caching.Analysis
Imports Aricie.DNN.Diagnostics
Imports Microsoft.Data.Caching

Namespace Aricie.DNN.Caching.Client.Velocity
    Public Class VelocityClientProvider
        Inherits CachingClientProvider(Of VelocityHostInfo, VelocityClusterSettings)

        Private _CacheFactory As Microsoft.Data.Caching.DataCacheFactory
        Private _DistributedCachingCache As Microsoft.Data.Caching.DataCache

        Private Shared _CacheLock As New Object

        Private ReadOnly Property CacheFactory() As Microsoft.Data.Caching.DataCacheFactory
            Get
                If Me._CacheFactory Is Nothing Then
                    'Dim velSettings As CachingClientSettings = DistributedCachingProvider.Settings.ClientSettings
                    If Me.ClusterSettings.Hosts.Count > 0 Then
                        Dim servers As New List(Of Microsoft.Data.Caching.DataCacheServerEndpoint)(Me.ClusterSettings.Hosts.Count)
                        For Each objHostInfo As VelocityHostInfo In Me.ClusterSettings.Hosts
                            Dim objHost As New Microsoft.Data.Caching.DataCacheServerEndpoint(objHostInfo.Name, objHostInfo.CachePort, objHostInfo.CacheHostName)
                            servers.Add(objHost)
                        Next
                        If DistributedCachingProviderBase.Settings.LoggingSettings.EnableStatsCollector Then
                            Dim nbEndPointsProp As New KeyValuePair(Of String, String)(CacheStepProperty.NbEndPoints, servers.Count.ToString)
                            DistributedCachingBusinessController.LogCachingOperation(CacheTimings.Init, "Config prepared", _
                                                                                     Aricie.DNN.Diagnostics.WorkingPhase.EndOverhead, False, "", True, nbEndPointsProp)
                        End If
                        Me._CacheFactory = New Microsoft.Data.Caching.DataCacheFactory(servers.ToArray, True, False, _
                                                                                       Microsoft.Data.Caching.DataCacheLocalCacheSyncPolicy.NotificationBased, _
                                                                                      Convert.ToInt32(Me.SpecificClusterSettings.ClientTimeout.Value.TotalMilliseconds), _
                                                                                      Convert.ToInt32(Me.SpecificClusterSettings.PollingInterval.Value.TotalSeconds))
                        If DistributedCachingProviderBase.Settings.LoggingSettings.EnableStatsCollector Then
                            DistributedCachingBusinessController.LogCachingOperation(CacheTimings.Init, "Factory created", _
                                                                                     Aricie.DNN.Diagnostics.WorkingPhase.EndOverhead, False, "", True)
                        End If
                    Else
                        Throw New ApplicationException("DistributedCaching Engine was enabled with no DistributedCaching Host Configured, please review configuration")
                    End If
                End If
                Return Me._CacheFactory
            End Get
        End Property

        Public ReadOnly Property VelocityCache() As Microsoft.Data.Caching.DataCache
            Get
                If _DistributedCachingCache Is Nothing Then
                    SyncLock _CacheLock
                        If _DistributedCachingCache Is Nothing Then
                            Try
                                Dim tempCache As Microsoft.Data.Caching.DataCache
                                If DistributedCachingProviderBase.Settings.LoggingSettings.EnableStatsCollector Then
                                    DistributedCachingBusinessController.LogCachingOperation(CacheTimings.Init, "Init Start", _
                                                                                             Aricie.DNN.Diagnostics.WorkingPhase.InProgress, False, "", False)
                                End If
                                If String.IsNullOrEmpty(Me.SpecificClusterSettings.CacheName) Then
                                    tempCache = CacheFactory.GetDefaultCache()
                                Else
                                    tempCache = CacheFactory.GetCache(Me.SpecificClusterSettings.CacheName)
                                End If
                                _DistributedCachingCache = tempCache
                                Me.SetCurrentStatus(DistributedCachingStatus.Started)
                                If DistributedCachingProviderBase.Settings.LoggingSettings.EnableStatsCollector Then
                                    DistributedCachingBusinessController.LogCachingOperation(CacheTimings.Init, "Cache created", Aricie.DNN.Diagnostics.WorkingPhase.InProgress, True, "", True)
                                End If
                            Catch dcex As DataCacheException
                                Me.DisableTemporary()
                                Me.ProcessDataCacheException(dcex, DistributedCachingProviderBase.Settings.CloudSettings.DefaultJob)
                            End Try
                        End If
                    End SyncLock
                End If
                Return _DistributedCachingCache
            End Get
        End Property

#Region "Overrides"

        Public Overrides Function [Get](ByVal objCacheJob As CacheJob) As WrappedCacheObject

            Try
                Dim toreturn As WrappedCacheObject = Nothing
                Select Case objCacheJob.Strategy.ConcurrencyMode
                    Case ConcurrencyMode.NoConcurrency
                        If objCacheJob.Strategy.RegionName = "" Then
                            toreturn = DirectCast(VelocityCache.Get(objCacheJob.Key), WrappedCacheObject)
                        Else
                            toreturn = DirectCast(VelocityCache.Get(objCacheJob.Key, objCacheJob.Strategy.RegionName), WrappedCacheObject)
                        End If
                    Case ConcurrencyMode.Optimistic, ConcurrencyMode.PessimisticPut
                        Dim objVersion As DataCacheItemVersion = Nothing
                        If objCacheJob.Strategy.RegionName = "" Then
                            toreturn = DirectCast(VelocityCache.Get(objCacheJob.Key, objVersion), WrappedCacheObject)
                        Else
                            toreturn = DirectCast(VelocityCache.Get(objCacheJob.Key, objVersion, objCacheJob.Strategy.RegionName), WrappedCacheObject)
                        End If
                        If toreturn IsNot Nothing Then
                            Me.SetItemVersion(objCacheJob.Key, objVersion)
                        Else
                            Me.RemoveItemVersion(objCacheJob.Key)
                        End If
                    Case ConcurrencyMode.PessimisticGet
                        Dim lockHandle As DataCacheLockHandle = DirectCast(Me.GetItemVersion(objCacheJob.Key), DataCacheLockHandle)
                        'todo: apparently, some locks get lost and become deadlocks
                        If lockHandle IsNot Nothing Then
                            If objCacheJob.Strategy.RegionName = "" Then
                                Me.VelocityCache.Unlock(objCacheJob.Key, lockHandle)
                            Else
                                Me.VelocityCache.Unlock(objCacheJob.Key, lockHandle, objCacheJob.Strategy.RegionName)
                            End If
                        End If
                        If objCacheJob.Strategy.RegionName = "" Then
                            toreturn = DirectCast(Me.VelocityCache.GetAndLock(objCacheJob.Key, Me.SpecificClusterSettings.PessimisticLockTimeout.Value, lockHandle), WrappedCacheObject)
                        Else
                            toreturn = DirectCast(Me.VelocityCache.GetAndLock(objCacheJob.Key, Me.SpecificClusterSettings.PessimisticLockTimeout.Value, lockHandle, objCacheJob.Strategy.RegionName), WrappedCacheObject)
                        End If
                        If lockHandle IsNot Nothing Then
                            Me.SetItemVersion(objCacheJob.Key, lockHandle)
                        End If
                End Select
                Return toreturn
            Catch dcex As DataCacheException
                If objCacheJob.Strategy.ConcurrencyMode <> ConcurrencyMode.NoConcurrency Then
                    Me.RemoveItemVersion(objCacheJob.Key)
                End If
                Me.ProcessDataCacheException(dcex, objCacheJob)
            End Try
            Return Nothing
        End Function

        Public Overrides Function MultipleGet(ByVal objCacheJob As CacheJob) As System.Collections.Generic.IEnumerable(Of System.Collections.Generic.KeyValuePair(Of String, WrappedCacheObject))
            Try

                Dim toReturn As IEnumerable(Of KeyValuePair(Of String, Object)) = Me.VelocityCache.GetObjectsByAnyTag(Me.GetGetTags(objCacheJob), objCacheJob.Strategy.RegionName)
                Return New Aricie.Collections.ConvertedEnumerable(Of KeyValuePair(Of String, Object), KeyValuePair(Of String, WrappedCacheObject))(toReturn, AddressOf Me.ConvertObjectToWrappedPair)
            Catch dcex As DataCacheException
                Me.ProcessDataCacheException(dcex, objCacheJob)
            End Try
            Return New List(Of KeyValuePair(Of String, WrappedCacheObject))
        End Function



        Public Overrides Function Put(ByVal objCacheJob As CachePutJob) As Boolean
            Dim newVersion As DataCacheItemVersion = Nothing
            Try
                Dim timeOut As TimeSpan = objCacheJob.GetTimeOut()

                Select Case objCacheJob.Job.Strategy.ConcurrencyMode
                    Case ConcurrencyMode.NoConcurrency
                        newVersion = Me.PutNoConcurrency(objCacheJob, timeOut, False)
                    Case ConcurrencyMode.Optimistic, ConcurrencyMode.PessimisticGet, ConcurrencyMode.PessimisticPut

                        Select Case objCacheJob.Job.Strategy.ConcurrencyMode
                            Case ConcurrencyMode.Optimistic
                                newVersion = Me.PutWithOptimisticConcurrency(objCacheJob, timeOut)
                            Case ConcurrencyMode.PessimisticPut
                                newVersion = Me.PutWithPessimisticPutConcurrency(objCacheJob, timeOut)
                            Case ConcurrencyMode.PessimisticGet
                                newVersion = Me.PutWithPessimisticGetConcurrency(objCacheJob, timeOut)
                        End Select
                        If objCacheJob.Job.Strategy.ConcurrencyMode = ConcurrencyMode.PessimisticGet Then
                            Me.RemoveItemVersion(objCacheJob.Job.Key)
                        Else
                            If newVersion IsNot Nothing Then
                                Me.SetItemVersion(objCacheJob.Job.Key, newVersion)
                            Else
                                Me.RemoveItemVersion(objCacheJob.Job.Key)
                            End If
                        End If

                End Select
                'If itemRemovedCallback IsNot Nothing Then
                '    Dim adapter As New CacheCallBackAdapter(itemRemovedCallback)
                '    Me.AddCallBack(objCacheJob.Job, AddressOf adapter.OnCacheNotificationCallBack)
                'End If
            Catch dcex As DataCacheException
                If objCacheJob.Job.Strategy.ConcurrencyMode <> ConcurrencyMode.NoConcurrency _
                AndAlso objCacheJob.Job.Strategy.ConcurrencyMode <> ConcurrencyMode.PessimisticGet Then
                    Me.RemoveItemVersion(objCacheJob.Job.Key)
                End If
                Me.ProcessDataCacheException(dcex, objCacheJob.Job)
            End Try
            Return newVersion IsNot Nothing
        End Function

        Public Overrides Function AddCallBack(ByVal objCacheJob As CacheJob, ByVal itemRemovedCallback As System.Web.Caching.CacheItemRemovedCallback) As Boolean
            Dim adapter As New VelocityCallBackAdapter(itemRemovedCallback)
            Return Me.InternalAddCallBack(objCacheJob, AddressOf adapter.OnCacheNotificationCallBack)

        End Function

        Public Overrides Sub Remove(ByVal objJob As CacheJob)

            Try
                If objJob.Strategy.RegionName = "" Then
                    Me.VelocityCache.Remove(objJob.Key)
                Else
                    Me.VelocityCache.Remove(objJob.Key, objJob.Strategy.RegionName)
                End If
            Catch dcex As DataCacheException
                Me.ProcessDataCacheException(dcex, objJob)
            End Try
        End Sub

        Public Overrides Sub ResetTimeOut(ByVal objCacheJob As CachePutJob)


            If objCacheJob.Value IsNot Nothing AndAlso objCacheJob.Value.GetType Is GetType(WrappedCacheObject) Then

                Try
                    Dim objWrapped As WrappedCacheObject = DirectCast(objCacheJob.Value, WrappedCacheObject)
                    If objCacheJob.Job.Strategy.RegionName = "" Then
                        Me.VelocityCache.ResetObjectTimeout(objCacheJob.Job.Key, objCacheJob.GetTimeOut())
                    Else
                        Me.VelocityCache.ResetObjectTimeout(objCacheJob.Job.Key, objCacheJob.GetTimeOut(), objCacheJob.Job.Strategy.RegionName)
                    End If

                Catch dcex As DataCacheException
                    Me.ProcessDataCacheException(dcex, objCacheJob.Job)
                End Try


            End If

        End Sub

        Public Overrides Sub [Stop]()
            MyBase.Stop()
            Me._CacheFactory = Nothing
            Me._DistributedCachingCache = Nothing
        End Sub

        Public Overrides Sub CreateRegion(ByVal objJob As CacheJob)

            Try
                Me.VelocityCache.CreateRegion(objJob.Strategy.RegionName, objJob.Strategy.EvictionsOn)
            Catch dcex As DataCacheException
                Me.ProcessDataCacheException(dcex, objJob)
            End Try


        End Sub

        Public Overrides Sub ClearRegion(ByVal objJob As CacheJob)

            Try
                Me.VelocityCache.ClearRegion(objJob.Strategy.RegionName)
            Catch dcex As DataCacheException
                Me.ProcessDataCacheException(dcex, objJob)
            End Try


        End Sub

        Public Overrides Sub DeleteRegion(ByVal objJob As CacheJob)

            Try
                Me.VelocityCache.RemoveRegion(objJob.Strategy.RegionName)
            Catch dcex As DataCacheException
                Me.ProcessDataCacheException(dcex, objJob)
            End Try


        End Sub

#End Region

#Region "Private methods"



        Private Function GetPutTags(ByVal objCacheJob As CacheJob) As List(Of DataCacheTag)
            Dim dcTags As New List(Of DataCacheTag)
            For Each strTag As String In objCacheJob.Strategy.PutTagsList
                dcTags.Add(New DataCacheTag(strTag))
            Next
            Return dcTags
        End Function

        Private Function GetGetTags(ByVal objCacheJob As CacheJob) As List(Of DataCacheTag)
            Dim dcTags As New List(Of DataCacheTag)
            For Each strTag As String In objCacheJob.Strategy.GetTagsList
                dcTags.Add(New DataCacheTag(strTag))
            Next
            Return dcTags
        End Function

        Private Function PutWithPessimisticGetConcurrency(ByVal objCacheJob As CachePutJob, ByVal timeOut As TimeSpan) As DataCacheItemVersion

            Dim toreturn As DataCacheItemVersion = Nothing
            Dim objVersion As Object = Me.GetItemVersion(objCacheJob.Job.Key)
            If objVersion IsNot Nothing Then
                Dim lockHandle As DataCacheLockHandle = DirectCast(objVersion, DataCacheLockHandle)
                If timeOut <> Cache.NoSlidingExpiration Then
                    If objCacheJob.Job.Strategy.RegionName = "" Then
                        If objCacheJob.Job.Strategy.PutTags <> "" Then
                            toreturn = Me.VelocityCache.PutAndUnlock(objCacheJob.Job.Key, objCacheJob.Value, lockHandle, timeOut, Me.GetPutTags(objCacheJob.Job))
                        Else
                            toreturn = Me.VelocityCache.PutAndUnlock(objCacheJob.Job.Key, objCacheJob.Value, lockHandle, timeOut)
                        End If

                    Else
                        If objCacheJob.Job.Strategy.PutTags <> "" Then
                            toreturn = Me.VelocityCache.PutAndUnlock(objCacheJob.Job.Key, objCacheJob.Value, lockHandle, timeOut, GetPutTags(objCacheJob.Job), objCacheJob.Job.Strategy.RegionName)
                        Else
                            toreturn = Me.VelocityCache.PutAndUnlock(objCacheJob.Job.Key, objCacheJob.Value, lockHandle, timeOut, objCacheJob.Job.Strategy.RegionName)
                        End If
                    End If

                Else
                    If objCacheJob.Job.Strategy.RegionName = "" Then
                        If objCacheJob.Job.Strategy.PutTags <> "" Then
                            toreturn = Me.VelocityCache.PutAndUnlock(objCacheJob.Job.Key, objCacheJob.Value, lockHandle, GetPutTags(objCacheJob.Job))
                        Else
                            toreturn = Me.VelocityCache.PutAndUnlock(objCacheJob.Job.Key, objCacheJob.Value, lockHandle)
                        End If

                    Else
                        If objCacheJob.Job.Strategy.PutTags <> "" Then
                            toreturn = Me.VelocityCache.PutAndUnlock(objCacheJob.Job.Key, objCacheJob.Value, lockHandle, GetPutTags(objCacheJob.Job), objCacheJob.Job.Strategy.RegionName)
                        Else
                            toreturn = Me.VelocityCache.PutAndUnlock(objCacheJob.Job.Key, objCacheJob.Value, lockHandle, objCacheJob.Job.Strategy.RegionName)
                        End If
                    End If
                End If
            ElseIf Me.Get(objCacheJob.Job) Is Nothing Then
                toreturn = Me.PutNoConcurrency(objCacheJob, timeOut, True)
            End If
            Return toreturn
        End Function

        Private Function PutWithPessimisticPutConcurrency(ByVal objCacheJob As CachePutJob, ByVal timeOut As TimeSpan) As DataCacheItemVersion

            Dim toreturn As DataCacheItemVersion = Nothing
            Dim objVersionAsObj As Object = Me.GetItemVersion(objCacheJob.Job.Key)
            If objVersionAsObj IsNot Nothing Then
                Dim objVersion As DataCacheItemVersion = Nothing
                Dim lockedObj As Object
                Dim lockHandle As DataCacheLockHandle = Nothing
                If objCacheJob.Job.Strategy.RegionName = "" Then
                    lockedObj = Me.VelocityCache.GetAndLock(objCacheJob.Job.Key, Me.SpecificClusterSettings.PessimisticLockTimeout.Value, lockHandle)
                Else
                    lockedObj = Me.VelocityCache.GetAndLock(objCacheJob.Job.Key, Me.SpecificClusterSettings.PessimisticLockTimeout.Value, lockHandle, objCacheJob.Job.Strategy.RegionName)
                End If
                If lockedObj IsNot Nothing Then
                    Try
                        objVersion = DirectCast(objVersionAsObj, DataCacheItemVersion)
                        Dim currObject As Object
                        If objCacheJob.Job.Strategy.RegionName = "" Then
                            currObject = Me.VelocityCache.GetIfNewer(objCacheJob.Job.Key, objVersion)
                        Else
                            currObject = Me.VelocityCache.GetIfNewer(objCacheJob.Job.Key, objVersion, objCacheJob.Job.Strategy.RegionName)
                        End If
                        If currObject Is Nothing Then
                            If timeOut <> Cache.NoSlidingExpiration Then
                                If objCacheJob.Job.Strategy.RegionName = "" Then
                                    If objCacheJob.Job.Strategy.PutTags <> "" Then
                                        toreturn = Me.VelocityCache.PutAndUnlock(objCacheJob.Job.Key, objCacheJob.Value, lockHandle, timeOut, Me.GetPutTags(objCacheJob.Job))
                                    Else
                                        toreturn = Me.VelocityCache.PutAndUnlock(objCacheJob.Job.Key, objCacheJob.Value, lockHandle, timeOut)
                                    End If

                                Else
                                    If objCacheJob.Job.Strategy.PutTags <> "" Then
                                        toreturn = Me.VelocityCache.PutAndUnlock(objCacheJob.Job.Key, objCacheJob.Value, lockHandle, timeOut, GetPutTags(objCacheJob.Job), objCacheJob.Job.Strategy.RegionName)
                                    Else
                                        toreturn = Me.VelocityCache.PutAndUnlock(objCacheJob.Job.Key, objCacheJob.Value, lockHandle, timeOut, objCacheJob.Job.Strategy.RegionName)
                                    End If
                                End If

                            Else
                                If objCacheJob.Job.Strategy.RegionName = "" Then
                                    If objCacheJob.Job.Strategy.PutTags <> "" Then
                                        toreturn = Me.VelocityCache.PutAndUnlock(objCacheJob.Job.Key, objCacheJob.Value, lockHandle, GetPutTags(objCacheJob.Job))
                                    Else
                                        toreturn = Me.VelocityCache.PutAndUnlock(objCacheJob.Job.Key, objCacheJob.Value, lockHandle)
                                    End If

                                Else
                                    If objCacheJob.Job.Strategy.PutTags <> "" Then
                                        toreturn = Me.VelocityCache.PutAndUnlock(objCacheJob.Job.Key, objCacheJob.Value, lockHandle, GetPutTags(objCacheJob.Job), objCacheJob.Job.Strategy.RegionName)
                                    Else
                                        toreturn = Me.VelocityCache.PutAndUnlock(objCacheJob.Job.Key, objCacheJob.Value, lockHandle, objCacheJob.Job.Strategy.RegionName)
                                    End If
                                End If
                            End If
                        Else
                            If objCacheJob.Job.Strategy.RegionName = "" Then
                                Me.VelocityCache.Unlock(objCacheJob.Job.Key, lockHandle)
                            Else
                                Me.VelocityCache.Unlock(objCacheJob.Job.Key, lockHandle, objCacheJob.Job.Strategy.RegionName)
                            End If
                        End If
                    Catch ex As Exception
                        If objCacheJob.Job.Strategy.RegionName = "" Then
                            Me.VelocityCache.Unlock(objCacheJob.Job.Key, lockHandle)
                        Else
                            Me.VelocityCache.Unlock(objCacheJob.Job.Key, lockHandle, objCacheJob.Job.Strategy.RegionName)
                        End If
                        Throw ex
                    End Try

                End If
            ElseIf Me.Get(objCacheJob.Job) Is Nothing Then
                toreturn = Me.PutNoConcurrency(objCacheJob, timeOut, True)
            End If
            Return toreturn
        End Function


        Private Function PutWithOptimisticConcurrency(ByVal objCacheJob As CachePutJob, ByVal timeOut As TimeSpan) As DataCacheItemVersion
            Dim toreturn As DataCacheItemVersion = Nothing
            Dim objVersion As DataCacheItemVersion = Nothing
            Dim objVersionAsObj As Object = Me.GetItemVersion(objCacheJob.Job.Key)
            If objVersionAsObj IsNot Nothing Then
                objVersion = DirectCast(objVersionAsObj, DataCacheItemVersion)
                If timeOut <> Cache.NoSlidingExpiration Then

                    If objCacheJob.Job.Strategy.RegionName = "" Then
                        If objCacheJob.Job.Strategy.PutTags <> "" Then
                            toreturn = Me.VelocityCache.Put(objCacheJob.Job.Key, objCacheJob.Value, objVersion, timeOut, Me.GetPutTags(objCacheJob.Job))
                        Else
                            toreturn = Me.VelocityCache.Put(objCacheJob.Job.Key, objCacheJob.Value, objVersion, timeOut)
                        End If

                    Else
                        If objCacheJob.Job.Strategy.PutTags <> "" Then
                            toreturn = Me.VelocityCache.Put(objCacheJob.Job.Key, objCacheJob.Value, objVersion, timeOut, GetPutTags(objCacheJob.Job), objCacheJob.Job.Strategy.RegionName)
                        Else
                            toreturn = Me.VelocityCache.Put(objCacheJob.Job.Key, objCacheJob.Value, objVersion, timeOut, objCacheJob.Job.Strategy.RegionName)
                        End If
                    End If

                Else
                    If objCacheJob.Job.Strategy.RegionName = "" Then
                        If objCacheJob.Job.Strategy.PutTags <> "" Then
                            toreturn = Me.VelocityCache.Put(objCacheJob.Job.Key, objCacheJob.Value, objVersion, GetPutTags(objCacheJob.Job))
                        Else
                            toreturn = Me.VelocityCache.Put(objCacheJob.Job.Key, objCacheJob.Value, objVersion)
                        End If

                    Else
                        If objCacheJob.Job.Strategy.PutTags <> "" Then
                            toreturn = Me.VelocityCache.Put(objCacheJob.Job.Key, objCacheJob.Value, objVersion, GetPutTags(objCacheJob.Job), objCacheJob.Job.Strategy.RegionName)
                        Else
                            toreturn = Me.VelocityCache.Put(objCacheJob.Job.Key, objCacheJob.Value, objVersion, objCacheJob.Job.Strategy.RegionName)
                        End If
                    End If
                End If
            Else
                'item created locally
                'only store if non existing
                If Me.Get(objCacheJob.Job) Is Nothing Then
                    toreturn = Me.PutNoConcurrency(objCacheJob, timeOut, True)
                End If
            End If
            Return toreturn
        End Function

        Private Function PutNoConcurrency(ByVal objCacheJob As CachePutJob, ByVal timeOut As TimeSpan, ByVal addItem As Boolean) As DataCacheItemVersion
            Dim toReturn As DataCacheItemVersion
            If timeOut <> Cache.NoSlidingExpiration Then

                If objCacheJob.Job.Strategy.RegionName = "" Then
                    If objCacheJob.Job.Strategy.PutTags <> "" Then
                        If addItem Then
                            toReturn = Me.VelocityCache.Add(objCacheJob.Job.Key, objCacheJob.Value, timeOut, Me.GetPutTags(objCacheJob.Job))
                        Else
                            toReturn = Me.VelocityCache.Put(objCacheJob.Job.Key, objCacheJob.Value, timeOut, Me.GetPutTags(objCacheJob.Job))
                        End If

                    Else
                        If addItem Then
                            toReturn = Me.VelocityCache.Add(objCacheJob.Job.Key, objCacheJob.Value, timeOut)
                        Else
                            toReturn = Me.VelocityCache.Put(objCacheJob.Job.Key, objCacheJob.Value, timeOut)
                        End If

                    End If

                Else
                    If objCacheJob.Job.Strategy.PutTags <> "" Then
                        If addItem Then
                            toReturn = Me.VelocityCache.Add(objCacheJob.Job.Key, objCacheJob.Value, timeOut, GetPutTags(objCacheJob.Job), objCacheJob.Job.Strategy.RegionName)
                        Else
                            toReturn = Me.VelocityCache.Put(objCacheJob.Job.Key, objCacheJob.Value, timeOut, GetPutTags(objCacheJob.Job), objCacheJob.Job.Strategy.RegionName)
                        End If

                    Else
                        If addItem Then
                            toReturn = Me.VelocityCache.Add(objCacheJob.Job.Key, objCacheJob.Value, timeOut, objCacheJob.Job.Strategy.RegionName)
                        Else
                            toReturn = Me.VelocityCache.Put(objCacheJob.Job.Key, objCacheJob.Value, timeOut, objCacheJob.Job.Strategy.RegionName)
                        End If

                    End If
                End If

            Else
                If objCacheJob.Job.Strategy.RegionName = "" Then


                    If objCacheJob.Job.Strategy.PutTags <> "" Then
                        If addItem Then
                            toReturn = Me.VelocityCache.Add(objCacheJob.Job.Key, objCacheJob.Value, GetPutTags(objCacheJob.Job))
                        Else
                            toReturn = Me.VelocityCache.Put(objCacheJob.Job.Key, objCacheJob.Value, GetPutTags(objCacheJob.Job))
                        End If

                    Else
                        If addItem Then
                            toReturn = Me.VelocityCache.Add(objCacheJob.Job.Key, objCacheJob.Value)
                        Else
                            toReturn = Me.VelocityCache.Put(objCacheJob.Job.Key, objCacheJob.Value)
                        End If

                    End If

                Else
                    If objCacheJob.Job.Strategy.PutTags <> "" Then
                        If addItem Then
                            toReturn = Me.VelocityCache.Add(objCacheJob.Job.Key, objCacheJob.Value, GetPutTags(objCacheJob.Job), objCacheJob.Job.Strategy.RegionName)
                        Else
                            toReturn = Me.VelocityCache.Put(objCacheJob.Job.Key, objCacheJob.Value, GetPutTags(objCacheJob.Job), objCacheJob.Job.Strategy.RegionName)
                        End If

                    Else
                        If addItem Then
                            toReturn = Me.VelocityCache.Add(objCacheJob.Job.Key, objCacheJob.Value, objCacheJob.Job.Strategy.RegionName)
                        Else
                            toReturn = Me.VelocityCache.Put(objCacheJob.Job.Key, objCacheJob.Value, objCacheJob.Job.Strategy.RegionName)
                        End If

                    End If

                End If
            End If
            Return toReturn
        End Function

        Private Function InternalAddCallBack(ByVal objJob As CacheJob, ByVal clientCallBack As DataCacheNotificationCallback) As Boolean
            Dim toReturn As Boolean
            Dim ndItemUpdateOps As Microsoft.Data.Caching.DataCacheNotificationDescriptor = Nothing
            Try

                If objJob.Strategy.RegionName = "" Then
                    ndItemUpdateOps = Me.VelocityCache.AddItemLevelCallback(objJob.Key, Microsoft.Data.Caching.DataCacheOperation.RemoveItem, clientCallBack)
                Else
                    ndItemUpdateOps = Me.VelocityCache.AddItemLevelCallback(objJob.Key, Microsoft.Data.Caching.DataCacheOperation.RemoveItem, clientCallBack, objJob.Strategy.RegionName)
                End If
                toReturn = True
            Catch dcex As DataCacheException
                Me.ProcessDataCacheException(dcex, objJob)
            End Try
            Return toReturn

        End Function

        Private Sub ProcessDataCacheException(ByVal dcex As DataCacheException, ByVal objJob As CacheJob)
            Dim status As String = "ErrStatus.UNKNOWN"
            Select Case dcex.ErrorCode
                Case &H16
                    status = "ErrStatus.INTERNAL_ERROR, ErrStatus.NO_WRITE_QUORUM, ErrStatus.CHANNEL_CLOSED, ErrStatus.REPLICATION_FAILED, ErrStatus.REGIONID_NOT_FOUND, ErrStatus.SLOT_LATCHED, ErrStatus.NOT_PRIMARY"
                    Me.DisableTemporary()
                    Exit Select
                Case 5
                    status = "ErrStatus.INVALID_REGION, ErrStatus.INVALID_CACHE"
                    Exit Select
                Case 9
                    status = "ErrStatus.REGION_ALREADY_EXISTS"
                    Exit Select
                Case &H17
                    status = "ErrStatus.TIMEOUT"
                    Exit Select
                Case 7
                    status = "ErrStatus.REGION_DOES_NOT_EXIST"
                    If Me.SpecificClusterSettings.AutoCreateRegions Then
                        Me.CreateRegion(objJob)
                    End If
                    Exit Select
                Case 1
                    status = "ErrStatus.VERSION_MISMATCH"
                    Exit Select
                Case 10
                    status = "ErrStatus.KEY_ALREADY_EXISTS"
                    Exit Select
                Case 8
                    status = "ErrStatus.KEY_DOES_NOT_EXIST"
                    Exit Select
                Case 11
                    status = "ErrStatus.NAMED_CACHE_DOES_NOT_EXIST"
                    Exit Select
                Case 12
                    status = "ErrStatus.MAX_NAMED_CACHE_COUNT_EXCEEDED"
                    Exit Select
                Case 13
                    status = "ErrStatus.OBJECT_LOCKED"
                    Exit Select
                Case 14
                    status = "ErrStatus.OBJECT_NOT_LOCKED"
                    Exit Select
                Case 15
                    status = "ErrStatus.INVALID_LOCK"
                    Exit Select
                Case &H10
                    status = "ErrStatus.INVALID_ENUMERATOR"
                    Exit Select
                Case 4
                    status = "ErrStatus.OUT_OF_MEMORY"
                    Me.DisableTemporary()
                    Exit Select
                Case &H13
                    status = "ErrStatus.SERVER_DEAD"
                    Me.DisableTemporary()
                    Exit Select
                Case &H18
                    status = "ErrStatus.CLIENT_SERVER_VERSION_MISMATCH"
                    Exit Select
                Case Else
                    Exit Select
            End Select
            Me.AddError(New KeyValuePair(Of String, String)(status, dcex.Message))
            If DistributedCachingProviderBase.Settings.LoggingSettings.EnableDebugLogging Then
                Dim vEx As New VelocityCachingException(status, dcex, objJob.Key, objJob.Strategy.RegionName)
                Aricie.DNN.Diagnostics.AsyncLogger.Instance.AddException(vEx)
            End If
        End Sub

#End Region

    End Class
End Namespace